home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
a_utils
/
expanded.lha
/
expanded
/
src
/
GeOb.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-03-19
|
61KB
|
2,228 lines
//
// Linear-Affine-Projective Geometry Package
//
// GeOb.C
//
// $Header$
//
// William J.R. Longabaugh
// University of Washington
//
// Implementation of the linear-affine-projective geometry
// package described in William J.R. Longabaugh, "An Expanded
// System for Coordinate-Free Geometric Programming", Master's
// thesis, University of Washington, 1992.
//
// Copyright (c) 1992, William J.R. Longabaugh
// Copying, use and development for non-commercial purposes permitted.
// All rights for commercial use reserved.
// This software is unsupported and without warranty; it is
// provided "as is".
//
// ***********************************************************************
//
// Notes on efficiency:
//
// There is a note in the header file Geom.h on efficiency that is
// applicable here. Unfortunately, the casting of GeObs from one type to
// another is probably very common, and yet the "first cut"
// implementation used here is incredibly inefficient. Part of the
// problem is that the functions to do the casting (e.g. GeOb
// GeOb::MapTo(GeObType t)) use functions provided to the user (e.g. GeOb
// Map::operator()(GeOb& v)) to do their job. This means that LOTS of
// redundant checks are being done, and the object is being copied MANY
// times during the course of the casting (thanks to the functional
// semantics of the user functions). The next cut at improving the
// implementation should provide special functions, available ONLY to the
// implementing classes, that place their results in a designated
// location and avoid type checking/casting their arguments, e.g.
// GeOb Map::Apply(GeOb& v, GeOb* out);
// This approach would help a lot at making things more efficient.
//
// Lots of implementing functions use the approach to call CanMap()
// first to check if a map will succeed, and then calling MapTo(). They
// do this to make error messages to the user more meaningful, since
// errors will be reported by the function the user calls, and not a
// function lower down. However, this is very inefficient, since it
// means the GeOb is being checked if it is OK more than once. A better
// approach would have GeObs providing the function
// Boolean GeOb::MapTo(GeObType t, GeOb* out);
// (ONLY to the implementing classes) that would avoid object copying
// and return FALSE if the mapping could not be done.
//
// ***********************************************************************
#include <math.h>
#include "Lap.h"
static Scalar randval(void);
// ***********************************************************************
//
// This function returns a NON-ZERO integer in the range -10.0 to +10.0,
// cast to a Scalar:
//
#define RAND_RANGE 20
static Scalar randval()
{
#ifdef c_plusplus
long random();
#endif
Scalar retval;
while (TRUE) {
retval = (Scalar)((random() % RAND_RANGE) - (RAND_RANGE / 2));
if (retval != 0.0) break;
}
return retval;
}
// ***********************************************************************
// ***********************************************************************
//
// GeOb Class
//
// ***********************************************************************
// ***********************************************************************
//
// Private/protected member functions
//
// ***********************************************************************
//
// Used by various classes to create GeObs with given matrix
// representation:
//
GeOb::GeOb(GeObType g, Space& ins, Matrix& inm) : s(ins), m(inm)
{
type = ANY_GEOB;
holds = g;
}
// ***********************************************************************
//
// Dumps data for GeObs:
//
void GeOb::data_out(ostream &c, int indent, char* name)
{
char *ibloc = new char[indent + 1];
for (int i = 0; i < indent; i++) {
*(ibloc + i) = ' ';
}
*(ibloc + indent) = '\0';
c << ibloc << ast;
c << ibloc << name;
c << ibloc << "Type of GeOb: ";
GeObTypeOut(c, type);
c << "\n";
c << ibloc << "Currently holds: ";
GeObTypeOut(c, holds);
c << "\n";
if (holds != NULL_GEOB) {
c << ibloc << "Contained in space:\n";
s.debug_out(c, indent + ERR_IND);
c << ibloc << "Matrix representation of the object:\n";
m.debug_out(c, indent + ERR_IND);
}
c << ibloc << ast;
delete ibloc;
return;
}
// ***********************************************************************
//
// Public member functions
//
// ***********************************************************************
//
// Need to do memberwise initialization, since Matrix class members need
// to do memberwise initialization:
//
GeOb::GeOb(GeOb& g) : s(g.s), m(g.m)
{
type = ANY_GEOB;
holds = g.holds;
}
// ***********************************************************************
//
// Need to do memberwise assignment, since Matrix class members need
// to do memberwise assignment:
//
GeOb& GeOb::operator=(GeOb& g)
{
// If there is a mismatch between what the arg. holds and the type
// of this Geob, and this geob is not an ANY_GEOB, we need to cast.
// This checking needs to be done because of apparent assignment
// inheritance in g++ 1.37:
if ((type != ANY_GEOB) && (type != g.holds) && (g.holds != NULL_GEOB)) {
*this = g.MapTo(type);
} else {
holds = g.holds;
s = g.s;
m = g.m;
}
return (*this);
}
// ***********************************************************************
//
// Output for debugging:
//
void GeOb::debug_out(ostream &c, int indent)
{
static char* name = "GeOb Object\n";
this->data_out(c, indent, name);
return;
}
// ***********************************************************************
//
// If the multimap has zero arguments, we can cast it into a GeOb in
// the range space. If it is a first-order map into the reals, it can
// be cast into a vector in the dual space of the domain.
//
GeOb::GeOb(MultiMap& mp)
{
Boolean success = FALSE;
type = ANY_GEOB;
// Find out if it has zero arguments. If it does, do the cast.
// Get the matrix rep. of the object. It is possible, if the type
// is AFF_VECTOR, that the representation needs to be de-hoisted:
if (mp.FullyEvaluated()) {
m = mp.FullEvalRep();
s = mp.RangeSpace();
holds = s.NativeType();
if ((holds == AFF_VECTOR) && (m.Columns() != s.MatrixSize())) {
m *= Transpose(s.GetSpace(AFFINE).HoistTangent());
}
success = TRUE;
} else {
// Otherwise, check if it is a linear functional:
Space range(mp.RangeSpace());
Space domain(mp.DomainSpace());
if ((mp.Holds() == MULTI_LINEAR) && (range == Reals) &&
(domain.CPSpaceSize() == 1)) {
s = domain.Dual();
m = Matrix(1, s.MatrixSize());
holds = s.NativeType();
for (int i = 0; i < s.MatrixSize(); i++) {
m[0][i] = (mp.GetStdImage(i))[0][0];
}
success = TRUE;
}
}
// If it is neither, we have an error:
if (!success) {
errh.ErrorExit("GeOb::GeOb(MultiMap&)",
"MultiMap cannot be cast to a GeOb", mp);
}
}
// ***********************************************************************
//
// Casts maps that are unrestricted linear functionals into dual vectors:
//
GeOb::GeOb(Map& mp)
{
// Check the range and domain of the map. If the domain is not a
// subset, and the range is the Reals, the map can be converted
// into a Vector in the dual space of the domain:
SubSet Range(mp.Range());
SubSet Domain(mp.Domain());
Space embeds(Range.EmbeddingSpace());
type = ANY_GEOB;
if ((mp.Holds() == LIN_MAP) && (embeds == Reals) &&
Range.IsFullSpace() && Domain.IsFullSpace()) {
s = (Domain.EmbeddingSpace()).Dual();
m = Transpose(mp.MatrixRep());
holds = s.NativeType();
} else {
errh.ErrorExit("GeOb::GeOb(Map&)",
"Map is not an unrestricted linear functional", mp);
}
}
// ***********************************************************************
//
// Casts Scalars into vectors in the predefined space "Reals", using
// the standard basis, i.e. "1":
//
GeOb::GeOb(Scalar v) : s(Reals), m(IdentityMatrix(1) * v)
{
type = ANY_GEOB;
holds = VECTOR;
}
// ***********************************************************************
//
// Says if the GeOb is (or can be mapped to) a zero vector:
//
Boolean GeOb::IsZeroVector(void)
{
Matrix mat = m;
if ((holds != VECTOR) && (holds != AFF_VECTOR)) {
GeOb temp = this->MapTo(VECTOR);
mat = temp.m;
}
for (int i = 0; i < s.Dim(); i++) {
if (fabs(mat[0][i]) > EPSILON) {
return (FALSE);
}
}
return (TRUE);
}
// ***********************************************************************
//
// This returns the nth element of a vector or point tuple (a vector
// or point in a cartesian product space).
//
GeOb GeOb::operator[](int n)
{
GeOb temp(*this);
// By storing points using a standard frame, point
// extraction is pretty straightforward. If we were to
// use a simplex, we would need to sum some coordinates to get
// the coordinates to return.
// This only works if this GeOb is a vector, aff_vector, or point.
// If it is not, map it into the linearization space. No other attempt
// will be made to "find" a space that is a CP space. (The user may need to
// explicitly apply standard maps).
if ((holds != VECTOR) && (holds != AFF_VECTOR) && (holds != AFF_POINT)) {
temp = this->MapTo(VECTOR);
}
// Check that the integer is in the correct range:
Space tempsp(temp.SpaceOf());
if ((n >= tempsp.CPSpaceSize()) || (n < 0)) {
errh.ErrorExit("GeOb GeOb::operator[](int)",
"Specified n is invalid",
ErrVal("Value of n = ", n), temp);
}
// If the mapped object is an atomic object, just return it:
if (tempsp.CPSpaceSize() == 1) {
return (temp);
}
// Get the nth space in the tuple and its coordinate starting slot,
// and figure out the size of the matrix to build:
Space retspace = tempsp[n];
int slot = tempsp.StartSlot(n);
// Build the matrix. If this is a point, we need to tack on the
// trailing 1:
Matrix retmat(1, retspace.MatrixSize());
for (int i = 0; i < retspace.Dim(); i++) {
retmat[0][i] = (temp.m)[0][slot++];
}
if (retspace.Holds() == AFF_SPACE) {
retmat[0][retspace.Dim()] = 1.0;
}
GeOb retval(retspace.NativeType(), retspace, retmat);
return (retval);
}
// ***********************************************************************
//
// Like the above function, but it extracts all the elements from
// the tuple and returns them in a list:
GeObList GeOb::TupleElements(void)
{
GeOb temp(*this);
// Same comments apply here as with above function.
if ((holds != VECTOR) && (holds != AFF_VECTOR) && (holds != AFF_POINT)) {
temp = this->MapTo(VECTOR);
}
// Loop through all the elements, creating a new GeOb for each element,
// and adding it to the list of GeObs that is returned.
// (But if the mapped object is an atomic object, just return it):
Space tempsp(temp.SpaceOf());
int n = tempsp.CPSpaceSize();
GeObList retlist(n);
if (tempsp.CPSpaceSize() == 1) {
retlist[0] = temp;
return (retlist);
}
for (int j = 0; j < n; j++) {
Space retspace = tempsp[j];
int slot = tempsp.StartSlot(j);
// Build the matrix. If this is a point, we need to tack on the
// trailing 1:
Matrix retmat(1, retspace.MatrixSize());
for (int i = 0; i < retspace.Dim(); i++) {
retmat[0][i] = (temp.m)[0][slot++];
}
if (retspace.Holds() == AFF_SPACE) {
retmat[0][retspace.Dim()] = 1.0;
}
retlist[j] = GeOb(retspace.NativeType(), retspace, retmat);
}
return (retlist);
}
// ***********************************************************************
//
// IMPORTANT NOTE ON ALGEBRAIC AND APPLICATION OPERATIONS:
//
// In the following operations, it is considered to make sense to
// use these operators on vector equivalence classes (ec) (and affine
// vector equivalence classes). Since casting ec to vectors
// or affine vectors returns random elements, the result of the
// operations will also be typically random. While it is not
// recommended to use the operations on ec, the operations are
// included for completeness.
//
// ***********************************************************************
//
// FRIEND FUNCTION
// If the object is a vector, negate it. Otherwise, map it into
// the linearization space and negate it there (though try to keep
// operations in tangent spaces localized there).
//
GeOb operator-(GeOb& th)
{
if ((th.holds == VECTOR) || (th.holds == AFF_VECTOR)) {
GeOb retval(th.holds, th.s, -(th.m));
return (retval);
} else if (th.holds == AFF_VEC_EC) {
GeOb retval = th.MapTo(AFF_VECTOR);
retval.m = -(retval.m);
return (retval);
} else {
GeOb retval = th.MapTo(VECTOR);
retval.m = -(retval.m);
return (retval);
}
}
// ***********************************************************************
//
// FRIEND FUNCTION
// If both objects are vectors in the same space, add them. Try to
// keep operations in tangent spaces localized there. Otherwise,
// map objects to their Linearization spaces and add them there if the
// spaces match.
//
GeOb operator+(GeOb& th, GeOb& g)
{
static char* sig = "GeOb operator+(GeOb&, GeOb&)";
if (((th.holds == VECTOR) && (g.holds == VECTOR)) ||
((th.holds == AFF_VECTOR) && (g.holds == AFF_VECTOR))) {
if (th.s == g.s) {
GeOb retval(th.holds, th.s, th.m + g.m);
return (retval);
} else {
errh.ErrorExit(sig, "Spaces of operands do not match", th, g);
}
} else if (((th.holds == AFF_VECTOR) || (th.holds == AFF_VEC_EC)) &&
((g.holds == AFF_VEC_EC) || (g.holds == AFF_VECTOR))) {
GeOb retval = th.MapTo(AFF_VECTOR);
GeOb other = g.MapTo(AFF_VECTOR);
if (retval.s == other.s) {
retval.m = retval.m + other.m;
return (retval);
} else {
errh.ErrorExit(sig, "Spaces of operands do not match", th, g);
}
} else {
GeOb retval = th.MapTo(VECTOR);
GeOb other = g.MapTo(VECTOR);
if (retval.s == other.s) {
retval.m = retval.m + other.m;
return (retval);
} else {
errh.ErrorExit(sig, "Spaces of mapped operands do not match",
th, g, retval, other);
}
}
}
// ***********************************************************************
//
// FRIEND FUNCTION
// Handle subtraction just like addition:
//
GeOb operator-(GeOb& th, GeOb& g)
{
static char* sig = "GeOb operator-(GeOb&, GeOb&)";
if (((th.holds == VECTOR) && (g.holds == VECTOR)) ||
((th.holds == AFF_VECTOR) && (g.holds == AFF_VECTOR))) {
if (th.s == g.s) {
GeOb retval(th.holds, th.s, th.m - g.m);
return (retval);
} else {
errh.ErrorExit(sig, "Spaces of operands do not match", th, g);
}
} else if (((th.holds == AFF_VECTOR) || (th.holds == AFF_VEC_EC)) &&
((g.holds == AFF_VEC_EC) || (g.holds == AFF_VECTOR))) {
GeOb retval = th.MapTo(AFF_VECTOR);
GeOb other = g.MapTo(AFF_VECTOR);
if (retval.s == other.s) {
retval.m = retval.m - other.m;
return (retval);
} else {
errh.ErrorExit(sig, "Spaces of operands do not match", th, g);
}
} else {
GeOb retval = th.MapTo(VECTOR);
GeOb other = g.MapTo(VECTOR);
if (retval.s == other.s) {
retval.m = retval.m - other.m;
return (retval);
} else {
errh.ErrorExit(sig, "Spaces of mapped operands do not match",
th, g, retval, other);
}
}
}
// ***********************************************************************
//
// FRIEND FUNCTION
// This operation only make sense if one of the operands is a Vector
// in the special 1-dim space "Reals", in which case this is scalar
// multiplication. While it would be very nice to be able to define
// functions like "GeOb operator*(Scalar coeff, GeOb& g)" for efficient
// scalar multiplication, compiler ambiguity prevents this from being
// possible:
//
GeOb operator*(GeOb& th, GeOb& g)
{
GeOb temp;
Scalar coeff;
if (th.s == Reals) {
coeff = th.ToScalar();
temp = g;
} else if (g.s == Reals) {
coeff = g.ToScalar();
temp = th;
} else {
errh.ErrorExit("GeOb operator*(GeOb&, GeOb&)",
"Neither operand was a vector in space Reals", th, g);
}
// Try to keep operations local to tangent vector spaces:
if (temp.holds == AFF_VEC_EC) {
temp = temp.MapTo(AFF_VECTOR);
} else if ((temp.holds != VECTOR) && (temp.holds != AFF_VECTOR)) {
temp = temp.MapTo(VECTOR);
}
temp.m = temp.m * coeff;
return (temp);
}
// ***********************************************************************
//
// FRIEND FUNCTION
// Same as multiplication, using a reciprocal. The second argument
// must be the vector from the Reals, and it must be non-zero. Again
// having a function "GeOb operator/(GeOb& g, Scalar coeff)" would
// be great, but must be avoided to prevent compiler ambiguity:
//
GeOb operator/(GeOb& th, GeOb& g)
{
static char* sig = "GeOb operator/(GeOb&, GeOb&)";
Scalar coeff;
if (g.s == Reals) {
coeff = g.ToScalar();
} else {
errh.ErrorExit(sig, "Second operand was not a vector in space Reals",
th, g);
}
if (fabs(coeff) < EPSILON) {
errh.ErrorExit(sig, "Attempt to divide by zero",
ErrVal("Value of denominator = ", coeff), th);
}
// Try to keep operations local to tangent vector spaces:
if ((th.holds == VECTOR) || (th.holds == AFF_VECTOR)) {
GeOb retval(th.holds, th.s, th.m / coeff);
return (retval);
} else if (th.holds == AFF_VEC_EC) {
GeOb retval = th.MapTo(AFF_VECTOR);
retval.m = retval.m / coeff;
return (retval);
} else {
GeOb retval = th.MapTo(VECTOR);
retval.m = retval.m / coeff;
return (retval);
}
}
// ***********************************************************************
//
// Apply this object to the argument, which should be in the dual space.
// Try to keep operations local to tangent vector spaces if possible.
//
Scalar GeOb::Apply(GeOb& a)
{
static char* sig = "Scalar GeOb::Apply(GeOb&)";
// One of the objects is going to be in a dual space, and cannot
// be mapped (except maybe from an equivalence class). The other
// object should be mapped to the native type of the dual space.
GeObType firsttype;
GeObType othertype;
SRel thisrel = s.ThisSpaceIs();
SRel otherrel = a.SpaceOf().ThisSpaceIs();
if ((thisrel == TANG_DUAL) || (thisrel == LIN_DUAL)) {
firsttype = s.NativeType();
othertype = s.Dual().NativeType();
} else if ((otherrel == TANG_DUAL) || (otherrel == LIN_DUAL)) {
firsttype = a.SpaceOf().Dual().NativeType();
othertype = a.SpaceOf().NativeType();
} else {
errh.ErrorExit(sig, "One item must be in a dual space", *this, a);
}
GeOb first = this->MapTo(firsttype);
GeOb other = a.MapTo(othertype);
if (first.SpaceOf() == (other.SpaceOf()).Dual()) {
return ((first.m * Transpose(other.m))[0][0]);
} else {
errh.ErrorExit(sig, "Spaces of mapped operands are not duals",
*this, a, first, other);
}
}
// ***********************************************************************
//
// If the GeOb is a vector in a space that has a distinguished inner
// product (i.e. it is a Euclidean Vector Space), there is a
// mapping between vectors and dual vectors: v -> < ,v>.
//
GeOb GeOb::Dual(void)
{
static char* sig = "Vector GeOb::Dual(void)";
GeObList hold(2);
// This implementation uses the robust way to find the dual: partially
// evaluate the inner product MLM using this vector, then cast the
// resulting linear functional into the dual vector. While taking the
// transpose is MUCH faster, future changes to the system that permit
// arbitrary distinguished products would break the transpose route.
if ((holds == VECTOR) || (holds == AFF_VECTOR)) {
if (s.IsEuclidean()) {
hold[0] = *this;
return ((s.InnerProduct())(s, hold));
} else {
errh.ErrorExit(sig, "Vector in not in a Euclidean space", *this);
}
}
// If this GeOb is an affine vector ec, cast it to an affine vector.
// Otherwise cast it to a vector and go:
GeObType maptype = ((holds == AFF_VEC_EC) ? AFF_VECTOR : VECTOR);
GeOb mapped = this->MapTo(maptype);
if ((mapped.SpaceOf()).IsEuclidean()) {
hold[0] = mapped;
return ((mapped.SpaceOf().InnerProduct())(mapped.SpaceOf(), hold));
} else {
errh.ErrorExit(sig, "Mapped object not in a Euclidean space",
*this, mapped);
}
}
// ***********************************************************************
//
// Returns TRUE iff this object can be cast to the specified object.
// Code is so specific to each type of GeOb that it was decided to
// cast this GeOb down and let functions tailored for each type do
// the work. While this localizes the implementation, the use of
// downcasting is TERRIBLE for efficiency, since it means this
// GeOb is being recopied prior to the operation being performed:
//
Boolean GeOb::CanMapTo(GeObType t)
{
Boolean rv;
// Quick kill:
if (t == holds) return (TRUE);
// Need to cover all cases. Need to ask if this object is in
// the domain of the standard mapping to the given type.
switch (holds) {
case VECTOR:
rv = Vector(*this).CanMapTo(t);
break;
case AFF_POINT:
rv = APoint(*this).CanMapTo(t);
break;
case AFF_VECTOR:
rv = AVector(*this).CanMapTo(t);
break;
case VEC_EC:
rv = VectorEC(*this).CanMapTo(t);
break;
case AFF_VEC_EC:
rv = AVectorEC(*this).CanMapTo(t);
break;
case PROJ_POINT:
rv = PPoint(*this).CanMapTo(t);
break;
case NULL_GEOB:
case ANY_GEOB:
default:
errh.ErrorExit("Boolean GeOb::CanMapTo(GeObType)", "Illegal GeOb type",
ErrType("Type found =", holds, GEOBTYPES), *this);
break;
}
return (rv);
}
// ***********************************************************************
//
// This is the way to get the GeOb that results from standard mappings.
// Code is so specific to each type of GeOb that it was decided to
// cast this GeOb down and let functions tailored for each type do
// the work. Unfortunately, while this approach localizes the
// implementation, the use of downcasting is TERRIBLE for efficiency,
// since it involves this GeOb being recopied prior to the operation
// being performed (in fact, it means MapTo() is being called AGAIN,
// though it only executes the "quick kill" base case). This is
// particulary harmful for system efficiency given the frequency of
// mapping in many common operations (map application, algebraic
// operations). Another approach may be more desirable.
//
GeOb GeOb::MapTo(GeObType t)
{
GeOb rv;
// Quick kill:
if (t == holds) return (*this);
// Need to cover all cases.
switch (holds) {
case VECTOR:
rv = Vector(*this).MapTo(t);
break;
case AFF_POINT:
rv = APoint(*this).MapTo(t);
break;
case AFF_VECTOR:
rv = AVector(*this).MapTo(t);
break;
case VEC_EC:
rv = VectorEC(*this).MapTo(t);
break;
case AFF_VEC_EC:
rv = AVectorEC(*this).MapTo(t);
break;
case PROJ_POINT:
rv = PPoint(*this).MapTo(t);
break;
case NULL_GEOB:
case ANY_GEOB:
default:
errh.ErrorExit("GeOb GeOb::MapTo(GeObType)", "Illegal GeOb type",
ErrType("Type found =", holds, GEOBTYPES), *this);
break;
}
return (rv);
}
// ***********************************************************************
//
// It would be nice to be able to SET tuple elements using the []
// operator, but this doesn't work since a tuple is not implemented
// as a set of GeObs, and so we cannot return a reference to one of them.
//
GeOb GeOb::SetTupleElement(int n, GeOb& g)
{
static char* sig = "GeOb GeOb::SetTupleElement(int, GeOb&)";
GeOb temp(*this);
// First, this only works if this GeOb is a vector, aff_vector, or point.
// If it is not, map it into the linearization space. No other attempt
// will be made to "find" a space that is a CP space. (The user may need to
// explicitly apply standard maps).
if ((holds != VECTOR) && (holds != AFF_VECTOR) && (holds != AFF_POINT)) {
temp = this->MapTo(VECTOR);
}
// Check that the integer is in the correct range:
Space tempsp(temp.SpaceOf());
if ((n >= tempsp.CPSpaceSize()) || (n < 0)) {
errh.ErrorExit(sig, "Specified n is invalid",
ErrVal("Value of n = ", n), temp);
}
// If the mapped object is in an atomic space, setting the element
// reduces to returning the mapped argument GeOb, as long as the
// spaces match:
if (tempsp.CPSpaceSize() == 1) {
GeOb retval = g.MapTo(tempsp.NativeType());
if (tempsp == retval.SpaceOf()) {
return (retval);
} else {
errh.ErrorExit(sig, "Mapped GeOb is not in required space",
temp, tempsp, g, retval);
}
}
// Get the nth space in the tuple and its coordinate starting slot.
// Map the object to the necessary type:
Space slotspace = tempsp[n];
int slot = tempsp.StartSlot(n);
GeOb insert = g.MapTo(slotspace.NativeType());
// Check that the spaces match, and if they do, replace the
// coordinates in the required slots and return:
if (slotspace == insert.SpaceOf()) {
Matrix retmat(temp.m);
for (int i = 0; i < slotspace.Dim(); i++) {
retmat[0][slot++] = (insert.m)[0][i];
}
GeOb retval = GeOb(temp.Holds(), tempsp, retmat);
return (retval);
} else {
errh.ErrorExit(sig, "Mapped GeOb is not in required space",
temp, slotspace, g, insert);
}
}
// ***********************************************************************
//
// FRIEND FUNCTION
// Correspondence of GeObList is INFINITY->A, 0->B, 1->C.
// Given CR = (A,B;C,D) and list (A,B,C), this returns D:
//
PPoint CrossRatio(AugScalar v, GeObList& g)
{
static char* sig = "GeOb GeOb::CrossRatio(AugScalar, GeObList&)";
int i;
// The GeObList must consist of 3 objects that can be cast to
// co-linear points in the projective completion.
if (g.Length() != 3) {
errh.ErrorExit(sig, "List must contain 3 items", g);
}
// Cast the first GeOb and glean inportant info.
GeOb temp = g[0].MapTo(PROJ_POINT);
Space retsp = temp.SpaceOf();
int numcol = retsp.MatrixSize();
Matrix holdmat(2, numcol);
Matrix unitmat(1, numcol);
holdmat[0] = (temp.m)[0];
// Go through the rest of the list, casting and storing the
// matrix representation:
for (i = 1; i < 3; i++) {
temp = g[i].MapTo(PROJ_POINT);
if (temp.SpaceOf() != retsp) {
errh.ErrorExit(sig, "All items do not map to same space", g);
}
if (i == 1) {
holdmat[1] = (temp.m)[0];
} else {
unitmat[0] = (temp.m)[0];
}
}
// We need to make sure that the points are distinct and that they
// are all co-linear. Then we need to scale the rows
// of the matrix so they sum to the unit point matrix.
// Build an orthogonal basis using the first two vectors:
Matrix orthbas(2, numcol);
Scalar mag = sqrt((holdmat[0] * Transpose(holdmat[0]))[0][0]);
orthbas[0] = (holdmat[0] / mag)[0];
Scalar fac = (holdmat[1] * Transpose(orthbas[0]))[0][0];
orthbas[1] = (holdmat[1] - (fac * orthbas[0]))[0];
mag = sqrt((orthbas[1] * Transpose(orthbas[1]))[0][0]);
if (fabs(mag) < EPSILON) {
errh.ErrorExit(sig, "First two points are not distinct", g);
}
orthbas[1] = (orthbas[1] / mag)[0];
// Project the third point into the plane, and make sure this projection
// is essentially superfluous:
Matrix newunit = unitmat * Transpose(orthbas);
Matrix test = (newunit * orthbas) - unitmat;
for (i = 0; i < numcol; i++) {
if (fabs(test[0][i]) > EPSILON) {
errh.ErrorExit(sig, "Points are not collinear", g);
}
}
// Find how to scale the rows of the mapping matrix so they sum to
// the unit point:
Matrix coeff = newunit * Inverse(holdmat * Transpose(orthbas));
if ((fabs(coeff[0][0]) < EPSILON) || (fabs(coeff[0][1]) < EPSILON)) {
errh.ErrorExit(sig, "Third point is not distinct", g);
}
holdmat[0] = (holdmat[0] * coeff[0][0])[0];
holdmat[1] = (holdmat[1] * coeff[0][1])[0];
// That's it! Holdmat now holds the map from extended reals to
// all points on the line, so map and return:
GeOb retval(PROJ_POINT, retsp, v.GetMatrix() * holdmat);
return PPoint(retval);
}
// ***********************************************************************
//
// FRIEND FUNCTION
// Given a list of four collinear points (A,B,C,D) where at least
// three are distinct, this routine calculates the cross ratio
// (A,B;C,D).
//
AugScalar CrossRatioCalc(GeObList& g)
{
static char* sig = "AugScalar GeOb::CrossRatioCalc(GeObList&)";
int i;
// The GeObList must consist of 4 objects that can be cast to
// co-linear points in the projective completion:
if (g.Length() != 4) {
errh.ErrorExit(sig, "List must contain 4 items", g);
}
// Cast the first GeOb and glean inportant info.
GeOb temp = g[0].MapTo(PROJ_POINT);
Space chksp = temp.SpaceOf();
int numcol = chksp.MatrixSize();
Matrix holdmat(4, numcol);
holdmat[0] = (temp.m)[0];
// Go through the rest of the list, casting and storing the
// matrix representation:
for (i = 1; i < 4; i++) {
temp = g[i].MapTo(PROJ_POINT);
if (temp.SpaceOf() != chksp) {
errh.ErrorExit(sig, "All items do not map to same space", g);
}
holdmat[i] = (temp.m)[0];
}
// Build an orthogonal basis using the first two distinct points. If
// we encounter a duplication, just try the next point. If that also
// doesn't work, we have an error:
Boolean havedup = FALSE;
Matrix orthbas(2, numcol);
Scalar mag = sqrt((holdmat[0] * Transpose(holdmat[0]))[0][0]);
orthbas[0] = (holdmat[0] / mag)[0];
Matrix candidate = holdmat[1];
for (int trycount = 1; trycount <= 3; trycount++) {
if (trycount == 3) {
errh.ErrorExit(sig, "Three points are not distinct", g);
}
Scalar fac = (candidate * Transpose(orthbas[0]))[0][0];
orthbas[1] = (candidate - (fac * orthbas[0]))[0];
mag = sqrt((orthbas[1] * Transpose(orthbas[1]))[0][0]);
if (fabs(mag) < EPSILON) {
candidate = holdmat[2];
havedup = TRUE;
} else {
orthbas[1] = (orthbas[1] / mag)[0];
break;
}
}
// Project the points into the line specified by the basis we
// have constructed, and make sure this projection is essentially
// superfluous:
Matrix ppts(4, 2);
for (i = 0; i < 4; i++) {
ppts[i] = (holdmat[i] * Transpose(orthbas))[0];
Matrix testm = (ppts[i] * orthbas) - holdmat[i];
for (int j = 0; j < numcol; j++) {
if (fabs(testm[0][j]) > EPSILON) {
errh.ErrorExit(sig, "Points are not collinear", g);
}
}
}
// Use this 2-dim representation to calculate the cross product,
// using the formulation in Penna & Patterson pg. 163:
Scalar fac[4];
fac[0] = (ppts[0][0] * ppts[2][1]) - (ppts[2][0] * ppts[0][1]);
fac[1] = (ppts[1][0] * ppts[3][1]) - (ppts[3][0] * ppts[1][1]);
fac[2] = (ppts[1][0] * ppts[2][1]) - (ppts[2][0] * ppts[1][1]);
fac[3] = (ppts[0][0] * ppts[3][1]) - (ppts[3][0] * ppts[0][1]);
// Catch cases where we do not have enough distinct points:
Boolean iszero[4];
Boolean haveazero = FALSE;
Boolean multizero = FALSE;
Boolean allequal = TRUE;
for (i = 0; i < 4; i++) {
iszero[i] = (fabs(fac[i]) < EPSILON);
multizero = (multizero || (haveazero && iszero[i]));
haveazero = (haveazero || iszero[i]);
allequal = allequal && (fabs(fac[i] - fac[0]) < EPSILON);
}
if (multizero || allequal) {
errh.ErrorExit(sig, "Must have 3 distinct points", g);
}
AugScalar retval;
Scalar denom = fac[2] * fac[3];
if (fabs(denom) < EPSILON) {
retval = AugScalar(INFINITY);
} else {
retval = AugScalar((fac[0] * fac[1]) / denom);
}
return retval;
}
// ***********************************************************************
//
// Cast a GeOb that is in the one-dimensional space "Reals" into a
// Scalar. Cannot use operator Scalar() because resulting automatic
// casting causes ambiguity in algebraic operations.
//
Scalar GeOb::ToScalar(void)
{
if (s == Reals) {
return (m[0][0]);
} else {
errh.ErrorExit("Scalar GeOb::ToScalar(void)",
"Attempted to convert a GeOb not in space Reals to a scalar",
*this);
}
}
// ***********************************************************************
// ***********************************************************************
//
// Vector Class
//
// ***********************************************************************
// ***********************************************************************
//
// Public member functions
//
// ***********************************************************************
//
// Creates a vector tuple with two elements.
//
Vector::Vector(VSpace& ins, GeOb& v1, GeOb& v2)
{
type = VECTOR;
*this = Vector(ins, GeObList(v1, v2));
}
// ***********************************************************************
//
// Creates a vector tuple with three elements.
//
Vector::Vector(VSpace& ins, GeOb& v1, GeOb& v2, GeOb& v3)
{
type = VECTOR;
*this = Vector(ins, GeObList(v1, v2, v3));
}
// ***********************************************************************
//
// Need to do memberwise assignment, since matrix class members need
// to do memberwise assignment:
//
Vector& Vector::operator=(Vector& g)
{
holds = g.holds;
s = g.s;
m = g.m;
return (*this);
}
// ***********************************************************************
//
// Output for debugging:
//
void Vector::debug_out(ostream &c, int indent)
{
static char* name = "Vector Object\n";
this->data_out(c, indent, name);
return;
}
// ***********************************************************************
//
// Vector creation by specifying coordinates:
//
Vector::Vector(VBasis& b, ScalarList& a)
{
static char* sig = "Vector::Vector(VBasis&, ScalarList&)";
type = VECTOR;
holds = VECTOR;
s = b.SpaceOf();
if (s.ThisSpaceIs() == TANGENT) {
errh.ErrorExit(sig, "Basis is not in a non-tangent vector space", b, a);
}
if (a.Length() != s.Dim()) {
errh.ErrorExit(sig, "Incorrect number of coordinates specified", b, a);
}
Matrix hold(1, s.Dim());
for (int i = 0; i < s.Dim(); i++) {
hold[0][i] = a[i];
}
m = hold * b.Tostdb();
}
// ***********************************************************************
//
// Creates a vector tuple in the specified cartesian product space using
// the objects in the list:
//
Vector::Vector(VSpace& ins, GeObList &g)
{
static char* sig = "Vector::Vector(VSpace&, GeObList&)";
type = VECTOR;
holds = VECTOR;
s = ins;
m = Matrix(1, ins.MatrixSize());
// The space must be a non-Tangent Vector Space. The length of the list
// must be correct:
if (ins.NativeType() != VECTOR) {
errh.ErrorExit(sig, "Space is a tangent vector space", ins);
}
int n = g.Length();
if (n != ins.CPSpaceSize()) {
errh.ErrorExit(sig,
"Length of list does not match number of elements in space",
ins, g);
}
// Go through the list of objects, casting them into vectors or
// affine vectors as needed. Report an error if the object cannot
// be mapped into the required space:
for (int j = 0; j < n; j++) {
// Get the nth space in the tuple and its coordinate starting slot.
// Map the object to the necessary type:
Space slotspace = ins[j];
int slot = ins.StartSlot(j);
GeOb insert = (g[j]).MapTo(slotspace.NativeType());
// Check that the spaces match, and if they do, replace the
// coordinates in the required slots and go to the next object:
if (slotspace == insert.SpaceOf()) {
for (int i = 0; i < slotspace.Dim(); i++) {
m[0][slot++] = (insert.MatrixRep())[0][i];
}
} else {
errh.ErrorExit(sig, "Mapped GeOb is not in required space",
slotspace, g[j], insert);
}
}
}
// ***********************************************************************
Boolean Vector::CanMapTo(GeObType t)
{
Boolean rv;
// Quick kill:
if (t == holds) return (TRUE);
if ((s.ThisSpaceIs() == TANG_DUAL) || (s.ThisSpaceIs() == LIN_DUAL)) {
rv = ((t == VEC_EC) && !(this->IsZeroVector()));
} else {
switch (t) {
case AFF_POINT:
rv = (s.StdAffineSubset()).IsIn(*this);
break;
case AFF_VECTOR:
rv = ((s.LinearMapToRef(TANGENT)).Domain()).IsIn(*this);
break;
case AFF_VEC_EC:
rv = ((s.LinearMapToRef(TANGENT)).Domain()).IsIn(*this) &&
!(this->IsZeroVector());;
break;
case VEC_EC:
rv = !(this->IsZeroVector());
break;
case PROJ_POINT:
rv = (s.StdAffineSubset()).IsIn(*this);
break;
case VECTOR:
case NULL_GEOB:
case ANY_GEOB:
default:
errh.ErrorExit("Boolean Vector::CanMapTo(GeObType)",
"Illegal GeOb Type",
ErrType("Type specified =", t, GEOBTYPES));
break;
}
}
return (rv);
}
// ***********************************************************************
GeOb Vector::MapTo(GeObType t)
{
static char* sig = "GeOb Vector::MapTo(GeObType)";
GeOb rv;
// Quick kill:
if (t == holds) return (*this);
if ((s.ThisSpaceIs() == TANG_DUAL) || (s.ThisSpaceIs() == LIN_DUAL)) {
if ((t == VEC_EC) && !(this->IsZeroVector())) {
rv = GeOb(VEC_EC, s, m);
} else {
errh.ErrorExit(sig, "Impossible Map request", *this,
ErrType("Mapping from:", holds, GEOBTYPES),
ErrType("Mapping to:", t, GEOBTYPES));
}
} else {
switch (t) {
case AFF_POINT:
rv = (s.AffineMapToRef(AFFINE))(*this);
break;
case AFF_VECTOR:
rv = (s.LinearMapToRef(TANGENT))(*this);
break;
case AFF_VEC_EC:
if (!this->IsZeroVector()) {
rv = (s.LinearMapToRef(TANGENT))(*this);
rv = GeOb(AFF_VEC_EC, rv.SpaceOf(), rv.MatrixRep());
} else {
errh.ErrorExit(sig, "Can't map zero vector to affine vec. eq. class",
*this);
}
break;
case VEC_EC:
if (!this->IsZeroVector()) {
rv = GeOb(VEC_EC, s, m);
} else {
errh.ErrorExit(sig, "Can't map zero vector to vec. eq. class",
*this);
}
break;
case PROJ_POINT:
rv = (s.AffineMapToRef(PROJECT_COMP))(*this);
break;
case VECTOR:
case NULL_GEOB:
case ANY_GEOB:
default:
errh.ErrorExit(sig, "Illegal GeOb type",
ErrType("Type specified =", t, GEOBTYPES));
break;
}
}
return (rv);
}
// ***********************************************************************
// ***********************************************************************
//
// AVector Class
//
// ***********************************************************************
// ***********************************************************************
//
// Public member functions
//
// ***********************************************************************
AVector::AVector(VSpace& ins, GeOb& v1, GeOb& v2)
{
type = AFF_VECTOR;
*this = AVector(ins, GeObList(v1, v2));
}
// ***********************************************************************
AVector::AVector(VSpace& ins, GeOb& v1, GeOb& v2, GeOb& v3)
{
type = AFF_VECTOR;
*this = AVector(ins, GeObList(v1, v2, v3));
}
// ***********************************************************************
//
// Need to do memberwise assignment, since matrix class members need
// to do memberwise assignment:
//
AVector& AVector::operator=(AVector& g)
{
holds = g.holds;
s = g.s;
m = g.m;
return (*this);
}
// ***********************************************************************
//
// Output for debugging:
//
void AVector::debug_out(ostream &c, int indent)
{
static char* name = "AVector Object\n";
this->data_out(c, indent, name);
return;
}
// ***********************************************************************
//
// Vector creation by specifying coordinates wrt some basis:
//
AVector::AVector(Basis& b, ScalarList& a)
{
static char* sig = "AVector::AVector(Basis&, ScalarList&)";
int n;
Matrix dropdown;
type = AFF_VECTOR;
holds = AFF_VECTOR;
switch (b.Holds()) {
case FRAME:
case SIMPLEX:
s = (b.SpaceOf()).GetSpace(TANGENT);
n = b.SpaceOf().MatrixSize();
if (a.Length() != n) {
errh.ErrorExit(sig, "Incorrect number of coordinates specified", b, a);
}
dropdown = Transpose((b.SpaceOf()).HoistTangent());
if (b.Holds() == SIMPLEX) {
Scalar sum = 0.0;
for (int i = 0; i < n; i++) {
sum += a[i];
}
if (fabs(sum) > EPSILON) {
errh.ErrorExit(sig, "Scalars must sum to 0.0 for a simplex",
ErrVal("Sum = ", sum), a, b);
}
} else if (fabs(a[n - 1]) > EPSILON) {
errh.ErrorExit(sig, "Last scalar must equal 0.0 for a frame",
ErrVal("Value = ", a[n - 1]), b);
}
break;
case VBASIS:
s = b.SpaceOf();
n = s.MatrixSize();
if (a.Length() != n) {
errh.ErrorExit(sig, "Incorrect number of coordinates specified", b, a);
}
dropdown = IdentityMatrix(n);
break;
case HFRAME:
case NULL_BASIS:
case ANY_BASIS:
default:
errh.ErrorExit(sig, "Illegal basis type", b);
break;
}
// If a Frame or Simplex is used, we need to change the matrix representation
// down to the tangent space:
Matrix hold(1, n);
for (int i = 0; i < n; i++) {
hold[0][i] = a[i];
}
m = hold * b.Tostdb() * dropdown;
}
// ***********************************************************************
AVector::AVector(VSpace& ins, GeObList& g)
{
static char* sig = "AVector::AVector(VSpace&, GeObList&)";
type = AFF_VECTOR;
holds = AFF_VECTOR;
s = ins;
m = Matrix(1, ins.MatrixSize());
// The space must be a Tangent Vector Space. The length of the list
// must be correct:
if (ins.ThisSpaceIs() != TANGENT) {
errh.ErrorExit(sig, "Space is not a tangent vector space", ins);
}
int n = g.Length();
if (n != ins.CPSpaceSize()) {
errh.ErrorExit(sig,
"Length of list does not match number of elements in space",
ins, g);
}
// Go through the list of objects, casting them into affine vectors as
// needed. Report an error if the object cannot be mapped into the
// required space:
for (int j = 0; j < n; j++) {
// Get the nth space in the tuple and its coordinate starting slot.
// Map the object to the necessary type:
Space slotspace = ins[j];
int slot = ins.StartSlot(j);
GeOb insert = (g[j]).MapTo(slotspace.NativeType());
// Check that the spaces match, and if they do, replace the
// coordinates in the required slots and go to the next object:
if (slotspace == insert.SpaceOf()) {
for (int i = 0; i < slotspace.Dim(); i++) {
m[0][slot++] = (insert.MatrixRep())[0][i];
}
} else {
errh.ErrorExit(sig, "Mapped GeOb is not in required space",
slotspace, g[j], insert);
}
}
}
// ***********************************************************************
//
// Returns TRUE iff this AVector can be cast to the specified object:
//
Boolean AVector::CanMapTo(GeObType t)
{
Boolean rv;
// Quick kill:
if (t == holds) return (TRUE);
switch (t) {
case VECTOR:
rv = TRUE;
break;
case AFF_VEC_EC:
case VEC_EC:
rv = !(this->IsZeroVector());
break;
case AFF_POINT:
case PROJ_POINT:
rv = FALSE;
break;
case AFF_VECTOR:
case NULL_GEOB:
case ANY_GEOB:
default:
errh.ErrorExit("Boolean AVector::CanMapTo(GeObType)", "Illegal GeOb Type",
ErrType("Type specified =", t, GEOBTYPES));
break;
}
return (rv);
}
// ***********************************************************************
//
// Map the AVector to another type:
//
GeOb AVector::MapTo(GeObType t)
{
static char* sig = "GeOb AVector::MapTo(GeObType)";
GeOb rv;
// Quick kill:
if (t == holds) return (*this);
switch (t) {
case VECTOR:
rv = (s.LinearMapToRef(LINEARIZATION))(*this);
break;
case VEC_EC:
if (!this->IsZeroVector()) {
rv = (s.LinearMapToRef(LINEARIZATION))(*this);
rv = GeOb(VEC_EC, rv.SpaceOf(), rv.MatrixRep());
} else {
errh.ErrorExit(sig, "Can't map zero vector to vector eq. class",
*this);
}
break;
case AFF_VEC_EC:
if (!this->IsZeroVector()) {
rv = GeOb(AFF_VEC_EC, s, m);
} else {
errh.ErrorExit(sig, "Can't map zero vector to affine vec. eq. class",
*this);
}
break;
case AFF_POINT:
case PROJ_POINT:
errh.ErrorExit(sig, "Impossible map request", *this,
ErrType("Mapping from:", holds, GEOBTYPES),
ErrType("Mapping to:", t, GEOBTYPES));
break;
case AFF_VECTOR:
case NULL_GEOB:
case ANY_GEOB:
default:
errh.ErrorExit(sig, "Illegal GeOb type",
ErrType("Type specified =", t, GEOBTYPES));
break;
}
return (rv);
}
// ***********************************************************************
// ***********************************************************************
//
// VectorEC Class
//
// ***********************************************************************
//
// Public member functions
//
// ***********************************************************************
//
// Need to do memberwise assignment, since Matrix class members need
// to do memberwise assignment:
//
VectorEC& VectorEC::operator=(VectorEC& g)
{
holds = g.holds;
s = g.s;
m = g.m;
return (*this);
}
// ***********************************************************************
//
// Output for debugging:
//
void VectorEC::debug_out(ostream &c, int indent)
{
static char* name = "VectorEC Object\n";
this->data_out(c, indent, name);
return;
}
// ***********************************************************************
//
// Returns TRUE iff this VectorEC can be cast to the specified object:
//
Boolean VectorEC::CanMapTo(GeObType t)
{
Boolean rv;
// Quick kill:
if (t == holds) return (TRUE);
if ((s.ThisSpaceIs() == TANG_DUAL) || (s.ThisSpaceIs() == LIN_DUAL)) {
rv = (t == VECTOR);
} else {
switch (t) {
case AFF_POINT:
case AFF_VECTOR:
case AFF_VEC_EC:
{
GeOb test = this->MapTo(VECTOR);
rv = ((s.LinearMapToRef(TANGENT)).Domain()).IsIn(test);
if (t == AFF_POINT) rv = !rv;
}
break;
case VECTOR:
case PROJ_POINT:
rv = TRUE;
break;
case VEC_EC:
case NULL_GEOB:
case ANY_GEOB:
default:
errh.ErrorExit("Boolean VectorEC::CanMapTo(GeObType)",
"Illegal GeOb type",
ErrType("Type specified =", t, GEOBTYPES));
break;
}
}
return (rv);
}
// ***********************************************************************
//
// Map this VectorEC to another object:
//
GeOb VectorEC::MapTo(GeObType t)
{
static char* sig = "GeOb VectorEC::MapTo(GeObType)";
GeOb rv;
Scalar coeff;
// Quick kill:
if (t == holds) return (*this);
if ((s.ThisSpaceIs() == TANG_DUAL) || (s.ThisSpaceIs() == LIN_DUAL)) {
if (t == VECTOR) {
coeff = randval();
rv = GeOb(VECTOR, s, m * coeff);
} else {
errh.ErrorExit(sig, "Impossible map request", *this,
ErrType("Mapping from:", holds, GEOBTYPES),
ErrType("Mapping to:", t, GEOBTYPES));
}
} else {
switch (t) {
case AFF_POINT:
// Go through the back door, by mapping into projective space first!
rv = (s.ProjectiveMapToRef(PROJECT_COMP))(*this);
rv = ((rv.SpaceOf()).AffineMapToRef(AFFINE))(rv);
break;
case AFF_VECTOR:
coeff = randval();
rv = GeOb(VECTOR, s, m * coeff);
rv = (s.LinearMapToRef(TANGENT))(rv);
break;
case AFF_VEC_EC:
rv = GeOb(VECTOR, s, m);
rv = (s.LinearMapToRef(TANGENT))(rv);
rv = GeOb(AFF_VEC_EC, rv.SpaceOf(), rv.MatrixRep());
break;
case VECTOR:
coeff = randval();
rv = GeOb(VECTOR, s, m * coeff);
break;
case PROJ_POINT:
rv = (s.ProjectiveMapToRef(PROJECT_COMP))(*this);
break;
case VEC_EC:
case NULL_GEOB:
case ANY_GEOB:
default:
errh.ErrorExit(sig, "Illegal GeOb type",
ErrType("Type specified =", t, GEOBTYPES));
break;
}
}
return (rv);
}
// ***********************************************************************
// ***********************************************************************
//
// AVectorEC Class
//
// ***********************************************************************
// ***********************************************************************
//
// Public member functions
//
// ***********************************************************************
//
// Need to do memberwise assignment, since Matrix class members need
// to do memberwise assignment:
//
AVectorEC& AVectorEC::operator=(AVectorEC& g)
{
holds = g.holds;
s = g.s;
m = g.m;
return (*this);
}
// ***********************************************************************
//
// Output for debugging:
//
void AVectorEC::debug_out(ostream &c, int indent)
{
static char* name = "AVectorEC Object\n";
this->data_out(c, indent, name);
return;
}
// ***********************************************************************
//
// Returns TRUE iff this AVectorEC can be cast to the specified object:
//
Boolean AVectorEC::CanMapTo(GeObType t)
{
Boolean rv;
// Quick kill:
if (t == holds) return (TRUE);
switch (t) {
case AFF_VECTOR:
case VEC_EC:
case VECTOR:
case PROJ_POINT:
rv = TRUE;
break;
case AFF_POINT:
rv = FALSE;
break;
case AFF_VEC_EC:
case NULL_GEOB:
case ANY_GEOB:
default:
errh.ErrorExit("Boolean AVectorEC::CanMapTo(GeObType)",
"Illegal GeOb type",
ErrType("Type specified =", t, GEOBTYPES));
break;
}
return (rv);
}
// ***********************************************************************
//
// This is the way to get the GeOb that results from standard mappings:
//
GeOb AVectorEC::MapTo(GeObType t)
{
static char* sig = "GeOb AVectorEC::MapTo(GeObType)";
GeOb rv;
Scalar coeff;
// Quick kill:
if (t == holds) return (*this);
switch (t) {
case VEC_EC:
rv = GeOb(AFF_VECTOR, s, m);
rv = (s.LinearMapToRef(LINEARIZATION))(rv);
rv = GeOb(VEC_EC, rv.SpaceOf(), rv.MatrixRep());
break;
case VECTOR:
coeff = randval();
rv = GeOb(AFF_VECTOR, s, m * coeff);
rv = (s.LinearMapToRef(LINEARIZATION))(rv);
break;
case AFF_VECTOR:
coeff = randval();
rv = GeOb(AFF_VECTOR, s, m * coeff);
break;
case PROJ_POINT:
rv = GeOb(AFF_VECTOR, s, m);
rv = (s.LinearMapToRef(LINEARIZATION))(rv);
rv = GeOb(VEC_EC, rv.SpaceOf(), rv.MatrixRep());
rv = (rv.SpaceOf().ProjectiveMapToRef(PROJECT_COMP))(rv);
break;
case AFF_POINT:
errh.ErrorExit(sig, "Impossible map request", *this,
ErrType("Mapping from:", holds, GEOBTYPES),
ErrType("Mapping to:", t, GEOBTYPES));
break;
case AFF_VEC_EC:
case NULL_GEOB:
case ANY_GEOB:
default:
errh.ErrorExit(sig, "Illegal GeOb type",
ErrType("Type specified =", t, GEOBTYPES));
break;
}
return (rv);
}
// ***********************************************************************
// ***********************************************************************
//
// APoint Class
//
// ***********************************************************************
// ***********************************************************************
//
// Public member functions
//
// ***********************************************************************
APoint::APoint(ASpace& ins, GeOb& v1, GeOb& v2)
{
type = AFF_POINT;
*this = APoint(ins, GeObList(v1, v2));
}
// ***********************************************************************
APoint::APoint(ASpace &ins, GeOb &v1, GeOb &v2, GeOb &v3)
{
type = AFF_POINT;
*this = APoint(ins, GeObList(v1, v2, v3));
}
// ***********************************************************************
//
// Need to do memberwise assignment, since Matrix class members need
// to do memberwise assignment:
//
APoint& APoint::operator=(APoint& g)
{
holds = g.holds;
s = g.s;
m = g.m;
return (*this);
}
// ***********************************************************************
//
// Output for debugging:
//
void APoint::debug_out(ostream &c, int indent)
{
static char* name = "APoint Object\n";
this->data_out(c, indent, name);
return;
}
// ***********************************************************************
//
// APoint creation by specifying coordinates wrt some basis:
//
APoint::APoint(Basis& b, ScalarList& a)
{
static char* sig = "APoint::APoint(Basis&, ScalarList&)";
holds = AFF_POINT;
type = AFF_POINT;
s = b.SpaceOf();
int n = s.MatrixSize();
if (a.Length() != n) {
errh.ErrorExit(sig, "Incorrect number of coordinates specified", b, a);
}
if (b.Holds() == FRAME) {
if (fabs(1.0 - a[n - 1]) > EPSILON) {
errh.ErrorExit(sig, "Last scalar must equal 1.0 for a frame",
ErrVal("Value = ", a[n - 1]), b);
}
} else if (b.Holds() == SIMPLEX) {
Scalar sum = 0.0;
for (int i = 0; i < n; i++) {
sum += a[i];
}
if (fabs(1.0 - sum) > EPSILON) {
errh.ErrorExit(sig, "Scalars must sum to 1.0 for a simplex",
ErrVal("Sum = ", sum), a, b);
}
} else {
errh.ErrorExit(sig, "Illegal basis type", b);
}
Matrix hold(1, n);
for (int i = 0; i < n; i++) {
hold[0][i] = a[i];
}
m = hold * b.Tostdb();
}
// ***********************************************************************
//
// Create a Point tuple:
//
APoint::APoint(ASpace& ins, GeObList& g)
{
static char* sig = "APoint::APoint(ASpace&, GeObList&)";
int slot;
type = AFF_POINT;
holds = AFF_POINT;
s = ins;
m = Matrix(1, ins.MatrixSize());
// The space must be an Affine Space. The length of the list must
// be correct:
int n = g.Length();
if (n != ins.CPSpaceSize()) {
errh.ErrorExit(sig,
"Length of list does not match number of elements in space",
ins, g);
}
// Go through the list of objects, casting them into points as needed.
// Report an error if the object cannot be mapped into the required space:
for (int j = 0; j < n; j++) {
// Get the nth space in the tuple and its coordinate starting slot.
// Map the object to the necessary type:
Space slotspace = ins[j];
slot = ins.StartSlot(j);
GeOb insert = (g[j]).MapTo(AFF_POINT);
// Check that the spaces match, and if they do, replace the
// coordinates in the required slots and go to the next object:
if (slotspace == insert.SpaceOf()) {
for (int i = 0; i < slotspace.Dim(); i++) {
m[0][slot++] = (insert.MatrixRep())[0][i];
}
} else {
errh.ErrorExit(sig, "Mapped GeOb is not in required space",
slotspace, g[j], insert);
}
}
// The last slot must be 1.0:
m[0][slot] = 1.0;
}
// ***********************************************************************
//
// Returns TRUE iff this APoint can be mapped to the specified type:
//
Boolean APoint::CanMapTo(GeObType t)
{
Boolean rv;
// Quick kill:
if (t == holds) return (TRUE);
switch (t) {
case AFF_VEC_EC:
case AFF_VECTOR:
rv = FALSE;
break;
case VECTOR:
case VEC_EC:
case PROJ_POINT:
rv = TRUE;
break;
case AFF_POINT:
case NULL_GEOB:
case ANY_GEOB:
default:
errh.ErrorExit("Boolean APoint::CanMapTo(GeObType)", "Illegal GeOb type",
ErrType("Type specified =", t, GEOBTYPES));
break;
}
return (rv);
}
// ***********************************************************************
//
// Maps this object to the specified type:
//
GeOb APoint::MapTo(GeObType t)
{
static char* sig = "GeOb APoint::MapTo(GeObType)";
GeOb rv;
// Quick kill:
if (t == holds) return (*this);
switch (t) {
case VECTOR:
rv = (s.AffineMapToRef(LINEARIZATION))(*this);
break;
case VEC_EC:
rv = (s.AffineMapToRef(LINEARIZATION))(*this);
rv = GeOb(VEC_EC, rv.SpaceOf(), rv.MatrixRep());
break;
case PROJ_POINT:
rv = (s.AffineMapToRef(PROJECT_COMP))(*this);
break;
case AFF_VEC_EC:
case AFF_VECTOR:
errh.ErrorExit(sig, "Impossible map request", *this,
ErrType("Mapping from:", holds, GEOBTYPES),
ErrType("Mapping to:", t, GEOBTYPES));
break;
case AFF_POINT:
case NULL_GEOB:
case ANY_GEOB:
default:
errh.ErrorExit(sig, "Illegal GeOb type",
ErrType("Type specified =", t, GEOBTYPES));
break;
}
return (rv);
}
// ***********************************************************************
// ***********************************************************************
//
// PPoint Class
//
// ***********************************************************************
// ***********************************************************************
//
// Public member functions
//
// ***********************************************************************
//
// Need to do memberwise assignment, since Matrix class members need
// to do memberwise assignment:
//
PPoint& PPoint::operator=(PPoint& g)
{
holds = g.holds;
s = g.s;
m = g.m;
return (*this);
}
// ***********************************************************************
//
// Output for debugging:
//
void PPoint::debug_out(ostream &c, int indent)
{
static char* name = "PPoint Object\n";
this->data_out(c, indent, name);
return;
}
// ***********************************************************************
//
// Projective Point creation by specifying homogeneous coordinates:
//
PPoint::PPoint(HFrame& b, ScalarList& a)
{
type = PROJ_POINT;
holds = PROJ_POINT;
s = b.SpaceOf();
if (a.Length() != s.MatrixSize()) {
errh.ErrorExit("PPoint::PPoint(HFrame&, ScalarList&)",
"Incorrect number of coordinates specified", b, a);
}
Matrix hold(1, s.MatrixSize());
for (int i = 0; i < s.MatrixSize(); i++) {
hold[0][i] = a[i];
}
m = hold * b.Tostdb();
}
// ***********************************************************************
//
// Returns TRUE iff the PPoint can be mapped to the specified object:
//
Boolean PPoint::CanMapTo(GeObType t)
{
Boolean rv;
// Quick kill:
if (t == holds) return (TRUE);
switch (t) {
case VECTOR:
case AFF_POINT:
rv = (s.StdAffineSubset()).IsIn(*this);
break;
case AFF_VEC_EC:
rv = !((s.StdAffineSubset()).IsIn(*this));
break;
case AFF_VECTOR:
rv = FALSE;
break;
case VEC_EC:
rv = TRUE;
break;
case PROJ_POINT:
case NULL_GEOB:
case ANY_GEOB:
default:
errh.ErrorExit("Boolean PPoint::CanMapTo(GeObType)", "Illegal GeOb type",
ErrType("Type specified =", t, GEOBTYPES));
break;
}
return (rv);
}
// ***********************************************************************
//
// This is the way to get the GeOb that results from standard mappings:
//
GeOb PPoint::MapTo(GeObType t)
{
static char* sig = "GeOb PPoint::MapTo(GeObType)";
GeOb rv;
// Quick kill:
if (t == holds) return (*this);
switch (t) {
case VECTOR:
rv = (s.AffineMapToRef(LINEARIZATION))(*this);
break;
case AFF_POINT:
rv = (s.AffineMapToRef(AFFINE))(*this);
break;
case VEC_EC:
rv = (s.ProjectiveMapToRef(LINEARIZATION))(*this);
break;
case AFF_VEC_EC:
rv = (s.ProjectiveMapToRef(LINEARIZATION))(*this);
rv = GeOb(VECTOR, rv.SpaceOf(), rv.MatrixRep());
rv = (rv.SpaceOf().LinearMapToRef(TANGENT))(rv);
rv = GeOb(AFF_VEC_EC, rv.SpaceOf(), rv.MatrixRep());
break;
case AFF_VECTOR:
errh.ErrorExit(sig, "Impossible Map request", *this,
ErrType("Mapping from:", holds, GEOBTYPES),
ErrType("Mapping to:", t, GEOBTYPES));
break;
case PROJ_POINT:
case NULL_GEOB:
case ANY_GEOB:
default:
errh.ErrorExit(sig, "Illegal GeOb Type",
ErrType("Type specified =", t, GEOBTYPES));
break;
}
return (rv);
}
// ***********************************************************************
// ***********************************************************************
//
// Create a "standard" Null GeOb that can be used for building lists
// of geometric object arguments for partial multimap evaluation:
//
GeOb NullGeOb;
// ***********************************************************************